﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quicklight.Web.Regions;
using System.Html;
using Quicklight.Web.Injection;
using Quicklight.Web.Commands;
using Quicklight.Web.Html;

namespace Quicklight.Web.Razor {

   /// <summary>
   /// To create a new view, create a file with the extension .cshtml. Ensure that you have installed the extension 'Razor Generator' under Tools > Extension Manager.
   /// Change the Custom Tool of the new view in its Properties to 'RazorGenerator'. Change the first line of the view to @* Generator: Template *@
   /// Have the view inherit from this BrowserView class by using @inherits Quicklight.Web.Razor.BrowserView<TViewModel>, changing the TViewModel to the view model class of the view
   /// Create your view using HTML and your chosen UI library. Perform the binding between the view and the view model using the declarative binding methods @Binding()
   /// Alternatively, you can declare a functions region using @functions { }, within that region override the OnRendered method and within the OnRendered method using the Bind() methods to perform binding
   /// To make Intellisense work correctly, remember to place a copy of Quicklight.Web.dll in the bin directory of the project.
   /// You can also add a web.config file in the root of the project to reference the System.Web.Mvc library. 
   /// To do this, create a hierarchy of elements: system.web > compilation > assemblies > add
   /// On the add element create an assembly property with the value "System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
   /// </summary>
   /// <typeparam name="TViewModel">Type of the viewmodel used by the view</typeparam>
   public abstract class BrowserView<TViewModel> : IViewable {
      private TViewModel viewModel;
      private StringBuilder stringBuilder;
      private List<Region> regions;
      private Container container;
      private Dictionary<string, Binder> binders;

      /// <summary>
      /// Constructs a BrowserView by resolving the viewmodel using the ObjectManager
      /// </summary>
      protected BrowserView() {
         regions = new List<Region>();
         viewModel = ObjectManager.Instance.Resolve<TViewModel>();
         binders = new Dictionary<string, Binder>();
      }

      /// <summary>
      /// Gets the container that last called the Render method
      /// </summary>
      public Container Container {
         get {
            return container;
         }
      }

      /// <summary>
      /// Gets and sets the viewmodel used by the view
      /// </summary>
      public TViewModel ViewModel {
         get {
            return viewModel;
         }
         set {
            viewModel = value;
         }
      }

      /// <summary>
      /// This method is implemented by the Razor Generator and contains the code to Render the view as a string
      /// </summary>
      public abstract void Execute();

      /// <summary>
      /// Renders the view into the UI component refered to by the container supplied
      /// </summary>
      /// <param name="container">Refers to the UI component in which the view must render itself</param>
      public void Render(Container container) {
         this.container = container;

         OnRendering();

         stringBuilder = new StringBuilder();
         regions = new List<Region>();
         binders = new Dictionary<string, Binder>();

         Execute();

         Element element = null;
         if (String.IsNullOrEmpty(container.FullName))
            element = Window.Instance.Document.Body;
         else
            element = Window.Instance.Document.GetElementById(container.FullName);

         if (element != null) {
            element.InnerHTML = stringBuilder.ToString();

            foreach (Region region in regions)
               region.Render();

            foreach (string key in binders.Keys) {
               Binder binder = binders[key];
               binder.Bind(key);
            }

            OnRendered();
         }
      }

      /// <summary>
      /// Places the fullname of the container before the name and returns the resulting Id that can be used as the id for an HTML element
      /// </summary>
      /// <param name="name">Name to place after fullname of container</param>
      /// <returns>Id of HTML element</returns>
      protected string GetId(string name) {
         return container.FullName + "." + name;
      }

      /// <summary>
      /// Gets the HTML element with the specified id
      /// </summary>
      /// <param name="id">Id of the HTML element to get</param>
      /// <returns>HTML element with id equal to supplied id</returns>
      protected Element GetElement(string id) {
         return Window.Instance.Document.GetElementById(id);
      }

      /// <summary>
      /// Programmatic binding method that binds the command to the event, named eventName, on the window instance
      /// </summary>
      /// <param name="window">HTML window instance obtained by using System.Html.Window.Instance</param>
      /// <param name="eventName">Name of the event to bind the command to</param>
      /// <param name="command">Command that will be executed if event fires</param>
      protected void Bind(WindowInstance window, string eventName, ICommand command) {
         window.Bind(eventName, command);
      }

      /// <summary>
      /// Programmatic binding method that binds the handler to the event, named eventName, on the window instance
      /// </summary>
      /// <param name="window">HTML window instance obtained by using System.Html.Window.Instance</param>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Delegate that will be invoked if event fires</param>
      protected void Bind(WindowInstance window, string eventName, ElementEventHandler handler) {
         window.Bind(eventName, handler);
      }

      /// <summary>
      /// Programmatic binding method that binds the listener to the event, named eventName, on the window instance
      /// </summary>
      /// <param name="window">HTML window instance obtained by using System.Html.Window.Instance</param>
      /// <param name="eventName">Name of the event to bind the listener to</param>
      /// <param name="listener">Delegate that will be invoked if event fires</param>
      protected void Bind(WindowInstance window, string eventName, ElementEventListener listener) {
         window.Bind(eventName, listener);
      }

      /// <summary>
      /// Programmatic binding method that binds the command to the event, named eventName, on the document instance
      /// </summary>
      /// <param name="document">HTML document instance obtained by using System.Html.Document.Instance</param>
      /// <param name="eventName">Name of the event to bind the command to</param>
      /// <param name="command">Command that will be executed if event fires</param>
      protected void Bind(DocumentInstance document, string eventName, ICommand command) {
         document.Bind(eventName, command);
      }

      /// <summary>
      /// Programmatic binding method that binds the handler to the event, named eventName, on the document instance
      /// </summary>
      /// <param name="document">HTML document instance obtained by using System.Html.Document.Instance</param>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Delegate that will be invoked if event fires</param>
      protected void Bind(DocumentInstance document, string eventName, ElementEventHandler handler) {
         document.Bind(eventName, handler);
      }

      /// <summary>
      /// Programmatic binding method that binds the listener to the event, named eventName, on the document instance
      /// </summary>
      /// <param name="document">HTML document instance obtained by using System.Html.Document.Instance</param>
      /// <param name="eventName">Name of the event to bind the listener to</param>
      /// <param name="listener">Delegate that will be invoked if event fires</param>
      protected void Bind(DocumentInstance document, string eventName, ElementEventListener listener) {
         document.Bind(eventName, listener);
      }

      /// <summary>
      /// Programmatic binding method that binds the command to the event, named eventName, on the element with the specified id
      /// </summary>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="eventName">Name of the event to bind the command to</param>
      /// <param name="command">Command that will be executed if event fires</param>
      protected void Bind(string elementId, string eventName, ICommand command) {
         GetElement(elementId).Bind(eventName, command);
      }

      /// <summary>
      /// Programmatic binding method that binds the handler to the event, named eventName, on the element with the specified id
      /// </summary>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Delegate that will be invoked if event fires</param>
      protected void Bind(string elementId, string eventName, ElementEventHandler handler) {
         GetElement(elementId).Bind(eventName, handler);
      }

      /// <summary>
      /// Programmatic binding method that binds the listener to the event, named eventName, on the element with the specified id
      /// </summary>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="eventName">Name of the event to bind the listener to</param>
      /// <param name="listener">Delegate that will be invoked if event fires</param>
      protected void Bind(string elementId, string eventName, ElementEventListener listener) {
         GetElement(elementId).Bind(eventName, listener);
      }

      /// <summary>
      /// Programmatic binding method that binds the HandleEvent method on the handler to the event, named eventName, on the element with the specified id
      /// </summary>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Interface that implements a handler named HandleEvent</param>
      protected void Bind(string elementId, string eventName, IElementEventHandler handler) {
         GetElement(elementId).Bind(eventName, handler);
      }

      /// <summary>
      /// Programmatic binding method that binds the content of the list to the attribute. 
      /// If the content of the list changes the attribute will be updated with the result of the ToString method of the list
      /// </summary>
      /// <typeparam name="T">Type of items stored in the ObservableList list</typeparam>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="attribute">Attribute that will be updated with the content of the ObservableList</param>
      /// <param name="list">Observable list to use to bind to attribute</param>
      protected void Bind<T>(string elementId, string attribute, ObservableList<T> list) {
         GetElement(elementId).Bind<T>(attribute, list);
      }

      /// <summary>
      /// Programmatic binding method that binds the ObservableProperty to the attribute
      /// The update direction can be specified as well as the trigger for the update from the UI
      /// </summary>
      /// <typeparam name="T">Type that the ObservableProperty wraps</typeparam>
      /// <param name="elementId">id of the element whose attribute must be bound to the ObservableProperty</param>
      /// <param name="attribute">attribute that must be bound to the ObservableProperty</param>
      /// <param name="property">ObservableProperty that must be bound to the attribute</param>
      /// <param name="triggerElementId">Optional. If the element that has the trigger event is an element other than the element of the attribute, specify its id here</param>
      /// <param name="eventName">Optional. Default = "change". Name of the event that will trigger an update from the UI to the model</param>
      /// <param name="updateModel">Optional. Default = true. Boolean indicating if the trigger event occurs whether the ObservableProperty must be updated with the value of the attribute</param>
      /// <param name="updateUI">Optional. Default = true. Boolean indicating if changes in the ObservableProperty must propagate to the attribute</param>
      protected void Bind<T>(string elementId, string attribute, ObservableProperty<T> property, string triggerElementId = "", string eventName = "change", bool updateModel = true, bool updateUI = true) {
         GetElement(elementId).Bind<T>(attribute, property, triggerElementId, eventName, updateModel, updateUI);
      }

      /// <summary>
      /// Programmatic binding method that binds the CalculatedProperty to the attribute
      /// Any changes in the value of the CalculatedProperty will be propagated to the attribute
      /// </summary>
      /// <typeparam name="T">Type that the CalculatedProperty wraps</typeparam>
      /// <param name="elementId">id of the element whose attribute must be bound to the CalculatedProperty</param>
      /// <param name="attribute">attribute that must be bound to the CalculatedProperty</param>
      /// <param name="property">CalculatedProperty that must be bound to the attribute</param>
      protected void Bind<T>(string elementId, string attribute, CalculatedProperty<T> property) {
         GetElement(elementId).Bind<T>(attribute, property);
      }

      /// <summary>
      /// Programmatic binding method that binds the Validation instance to the attribute
      /// Any changes in the value of the Validation Message property will be propagated to the attribute
      /// </summary>
      /// <param name="elementId">id of the element whose attribute must be bound to the Validation Message property</param>
      /// <param name="attribute">attribute that must be bound to the Validation Message property</param>
      /// <param name="validation">Validation that must be bound to the attribute</param>
      protected void Bind(string elementId, string attribute, Validation validation) {
         GetElement(elementId).Bind(attribute, validation);
      }

      /// <summary>
      /// Programmatic binding method that binds the content of the list to the inner content of the element with id elementId. 
      /// If the content of the list changes the content of the element will be updated with the result of the ToString method of the list
      /// </summary>
      /// <typeparam name="T">Type of items stored in the ObservableList list</typeparam>
      /// <param name="elementId">id of element that will be used in binding</param>
      /// <param name="list">Observable list to use to bind to content of the element</param>
      protected void Bind<T>(string elementId, ObservableList<T> list) {
         GetElement(elementId).Bind(list);
      }

      /// <summary>
      /// Programmatic binding method that binds the ObservableProperty to the inner content of the element with id elementId. 
      /// If the value of the ObservableProperty changes, the inner content of the element will be updated
      /// </summary>
      /// <typeparam name="T">Type that the ObservableProperty wraps</typeparam>
      /// <param name="elementId">id of the element whose inner content must be bound to the ObservableProperty</param>
      /// <param name="property">ObservableProperty that must be bound to the content of the element</param>
      protected void Bind<T>(string elementId, ObservableProperty<T> property) {
         GetElement(elementId).Bind(property);
      }

      /// <summary>
      /// Programmatic binding method that binds the CalculatedProperty to the inner content of the element with id elementId
      /// Any changes in the value of the CalculatedProperty will be propagated to the inner content of the element
      /// </summary>
      /// <typeparam name="T">Type that the CalculatedProperty wraps</typeparam>
      /// <param name="elementId">id of the element whose content must be bound to the CalculatedProperty</param>
      /// <param name="property">CalculatedProperty that must be bound to the content of the element</param>
      protected void Bind<T>(string elementId, CalculatedProperty<T> property) {
         GetElement(elementId).Bind(property);
      }

      /// <summary>
      /// Programmatic binding method that binds the Validation instance to the inner content of the element with id elementId
      /// Any changes in the value of the Validation Message property will be propagated to the content of the element
      /// </summary>
      /// <param name="elementId">id of the element whose content must be bound to the Validation Message property</param>
      /// <param name="validation">Validation that must be bound to the content of the element</param>
      protected void Bind(string elementId, Validation validation) {
         GetElement(elementId).Bind(validation);
      }

      /// <summary>
      /// Declarative binding method that binds the command to the event, named eventName, on the element which the binding is declared
      /// For example <input type="button" value="Add" @Binding("click", ViewModel.AddCommand) />
      /// </summary>
      /// <param name="eventName">Name of the event to bind the command to</param>
      /// <param name="command">Command that will be executed if event fires</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(string eventName, ICommand command) {
         Binder binder = new CommandBinder(eventName, command);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the handler to the event, named eventName, on the element in which the binding is declared
      /// For example <input type="button" value="Add" @Binding("click", OnClickAdd) />
      /// </summary>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Delegate that will be invoked if event fires</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(string eventName, ElementEventHandler handler) {
         Binder binder = new ElementEventHandlerBinder(eventName, handler);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the listener to the event, named eventName, on the element in which the binding is declared
      /// For example <input type="button" value="Add" @Binding("click", OnClickAdd) />
      /// </summary>
      /// <param name="eventName">Name of the event to bind the listener to</param>
      /// <param name="listener">Delegate that will be invoked if event fires</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(string eventName, ElementEventListener listener) {
         Binder binder = new ElementEventListenerBinder(eventName, listener);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the HandleEvent method on the handler to the event, named eventName, on the element in which the binding is declared
      /// For example <input type="button" value="Add" @Binding("click", ViewModel.AddHandler) />
      /// </summary>
      /// <param name="eventName">Name of the event to bind the handler to</param>
      /// <param name="handler">Interface that implements a handler named HandleEvent</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(string eventName, IElementEventHandler handler) {
         Binder binder = new InterfaceElementEventHandlerBinder(eventName, handler);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the content of the list to the attribute on the element in which the binding is declared
      /// If the content of the list changes the attribute will be updated with the result of the ToString method of the list
      /// For example <input type="text" @Binding("value", ViewModel.Items) />
      /// </summary>
      /// <typeparam name="T">Type of items stored in the ObservableList list</typeparam>
      /// <param name="attribute">Attribute that will be updated with the content of the ObservableList</param>
      /// <param name="list">Observable list to use to bind to attribute</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(string attribute, ObservableList<T> list) {
         Binder binder = new ObservableListAttributeBinder<T>(attribute, list);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the ObservableProperty to the attribute on the element in which the binding is declared
      /// The update direction can be specified as well as the trigger for the update from the UI
      /// For example <input type="text" @Binding("value", ViewModel.X) />
      /// </summary>
      /// <typeparam name="T">Type that the ObservableProperty wraps</typeparam>
      /// <param name="attribute">attribute that must be bound to the ObservableProperty</param>
      /// <param name="property">ObservableProperty that must be bound to the attribute</param>
      /// <param name="triggerElementId">Optional. If the element that has the trigger event is an element other than the element of the attribute, specify its id here</param>
      /// <param name="eventName">Optional. Default = "change". Name of the event that will trigger an update from the UI to the model</param>
      /// <param name="updateModel">Optional. Default = true. Boolean indicating if the trigger event occurs whether the ObservableProperty must be updated with the value of the attribute</param>
      /// <param name="updateUI">Optional. Default = true. Boolean indicating if changes in the ObservableProperty must propagate to the attribute</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(string attribute, ObservableProperty<T> property, string triggerElementId = "", string eventName = "change", bool updateModel = true, bool updateUI = true) {
         Binder binder = new ObservablePropertyAttributeBinder<T>(attribute, property, triggerElementId, eventName, updateModel, updateUI);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }


      /// <summary>
      /// Declarative binding method that binds the CalculatedProperty to the attribute on the element in which the binding is declared
      /// Any changes in the value of the CalculatedProperty will be propagated to the attribute
      /// For example <input type="text" @Binding("value", ViewModel.Result) />
      /// </summary>
      /// <typeparam name="T">Type that the CalculatedProperty wraps</typeparam>
      /// <param name="attribute">attribute that must be bound to the CalculatedProperty</param>
      /// <param name="property">CalculatedProperty that must be bound to the attribute</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(string attribute, CalculatedProperty<T> property) {
         Binder binder = new CalculatedPropertyAttributeBinder<T>(attribute, property);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the Validation instance to the attribute on the element in which the binding is declared
      /// Any changes in the value of the Validation Message property will be propagated to the attribute
      /// For example <input type="text" @Binding("value", ViewModel.X.Validation) />
      /// </summary>
      /// <param name="attribute">attribute that must be bound to the Validation Message property</param>
      /// <param name="validation">Validation that must be bound to the attribute</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(string attribute, Validation validation) {
         Binder binder = new ValidationAttributeBinder(attribute, validation);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the content of the list to the inner content of the element in which the binding is declared
      /// If the content of the list changes the content of the element will be updated with the result of the ToString method of the list
      /// For example <div>@Binding(ViewModel.Items)</div>
      /// </summary>
      /// <typeparam name="T">Type of items stored in the ObservableList list</typeparam>
      /// <param name="list">Observable list to use to bind to content of the element</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(ObservableList<T> list) {
         Binder binder = new ObservableListContentBinder<T>(list);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the ObservableProperty to the inner content of the element in which the binding is declared
      /// If the value of the ObservableProperty changes, the inner content of the element will be updated
      /// For example <div>@Binding(ViewModel.X)</div>
      /// </summary>
      /// <typeparam name="T">Type that the ObservableProperty wraps</typeparam>
      /// <param name="property">ObservableProperty that must be bound to the content of the element</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(ObservableProperty<T> property) {
         Binder binder = new ObservablePropertyContentBinder<T>(property);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the CalculatedProperty to the inner content of the element in which the binding is declared
      /// Any changes in the value of the CalculatedProperty will be propagated to the inner content of the element
      /// For example <div>@Binding(ViewModel.Result)</div>
      /// </summary>
      /// <typeparam name="T">Type that the CalculatedProperty wraps</typeparam>
      /// <param name="property">CalculatedProperty that must be bound to the content of the element</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding<T>(CalculatedProperty<T> property) {
         Binder binder = new CalculatedPropertyContentBinder<T>(property);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Declarative binding method that binds the Validation instance to the inner content of the element in which the binding is declared
      /// Any changes in the value of the Validation Message property will be propagated to the content of the element
      /// For example <div style="color:Red;">@Binding(ViewModel.X.Validation)</div>
      /// </summary>
      /// <param name="validation">Validation that must be bound to the content of the element</param>
      /// <returns>String with element locator to be used by Razor view</returns>
      protected string Binding(Validation validation) {
         Binder binder = new ValidationContentBinder(validation);
         string key = GetBinderKey();
         binders.Add(key, binder);
         return binder.GetElementLocator(key);
      }

      /// <summary>
      /// Indicates that a new container should be created using the namespace of the this views container and the specified region name
      /// The new region therefore inherits the namespace from the current view.
      /// Using the current namespace as the name of the RegionManager and the specified regionName, a Region instance can be obtained.
      /// This Region instance can be used to load/show/render views in the region.
      /// It can also be used to pass parameters to the view, using the Parameters property of the Region
      /// </summary>
      /// <param name="regionName">Name to give to region. Can be used, along with namespace as RegionManager name, to obtain Region instance</param>
      /// <returns>Returns the string representing the HTML container for the Region</returns>
      protected string RenderRegion(string regionName) {
         return RenderRegion(regionName, container.NameSpace);
      }

      /// <summary>
      /// Indicates that a new container should be created using the specified namespace region name
      /// The new region therefore creates a new namespace for it and its child regions
      /// Using the specified namespace as the name of the RegionManager and the specified regionName, a Region instance can be obtained.
      /// This Region instance can be used to load/show/render views in the region.
      /// It can also be used to pass parameters to the view, using the Parameters property of the Region
      /// </summary>
      /// <param name="regionName">Name to give to the region. Can be used, along with namespace as RegionManager name, to obtain Region instance</param>
      /// <param name="managerName">NameSpace of the region and its child regions. Use as the name for the RegionManager</param>
      /// <returns>Returns the string representing the HTML container for the Region</returns>
      protected string RenderRegion(string regionName, string managerName) {
         Region region = RegionManager.GetManager(managerName).AddRegion(regionName);
         if (region != null)
            regions.Add(region);

         return String.Format("<div id='{0}' />", region.FullName);
      }

      /// <summary>
      /// Render the view in the last container that requested a render
      /// </summary>
      protected void Refresh() {
         Render(container);
      }

      /// <summary>
      /// This method is called just before rendering is to happen. 
      /// </summary>
      protected virtual void OnRendering() {
      }

      /// <summary>
      /// This method is called just after rendering has happened and all HTML elements are therefore part of the DOM and can be accessed programmatically
      /// Override this method to perform programmatic binding using the Bind() methods
      /// </summary>
      protected virtual void OnRendered() {
      }

      /// <summary>
      /// Used by the Razor Generator to write literal pieces of HTML markup
      /// </summary>
      /// <param name="o">HTML markup to append to HTML of view</param>
      protected void WriteLiteral(object o) {
         stringBuilder.Append(o);
      }

      /// <summary>
      /// Used by Razor Generator to write strings of markup from @ declarations
      /// </summary>
      /// <param name="o">HTML markup to append to HTML of view</param>
      protected void Write(object o) {
         stringBuilder.Append(o);
      }

      /// <summary>
      /// Creates a unique key to be used to create a locator for the declarative binding. 
      /// </summary>
      /// <returns>String of hexadecimal characters</returns>
      private string GetBinderKey() {
         string hexString = GetHexString() + GetHexString() + GetHexString() + GetHexString();
         int count = 0;

         string key = String.Format("{0}.{1}.{2}", container.NameSpace, hexString, count);
         while (binders.ContainsKey(key)) {
            count++;
            key = String.Format("{0}.{1}.{2}", container.NameSpace, hexString, count);
         }

         return key;
      }

      /// <summary>
      /// Used by GetBinderKey to create a short string of hexadecimal characters
      /// </summary>
      /// <returns>Short string of random hexadecimal characters</returns>
      private string GetHexString() {
         return String.Format("{0:X}", Math.Floor(Math.Random() * 0x10000));
      }
   }
}
